package com.cloudcc.boot.service;

import com.cloudcc.boot.entity.sap.*;
import com.cloudcc.boot.enums.SapTypeEnum;
import com.yangzg.cloudcc.openapi.exception.CloudccOpenApiException;
import com.yangzg.cloudcc.openapi.response.data.CloudccOpenApiUpsertResponse;
import com.yangzg.cloudcc.openapi.service.CloudccOpenApiService;
import com.yangzg.cloudcc.openapi.service.WebClientService;
import com.yangzg.cloudcc.openapi.utils.JacksonUtils;
import com.yangzg.developer.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.resources.ConnectionProvider;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Slf4j
@Service
public class SapService {

    private final WebClient webClient;

    private final SapEnumsProperties sapEnums;

    private final CloudccOpenApiService cloudccOpenApiService;

    @Value("${sap.push-order-url}")
    private String pushOrderUrl;

    public SapService(WebClientService webClientService,
                      @Value("${sap.auth.username}") String basicAuthUsername,
                      @Value("${sap.auth.password}") String basicAuthPassword, SapEnumsProperties sapEnums, CloudccOpenApiService cloudccOpenApiService) {
        this.sapEnums = sapEnums;
        this.cloudccOpenApiService = cloudccOpenApiService;
        this.webClient = webClientService
                .connectionProvider(
                        ConnectionProvider.builder("sap-connection-provider").build())
                .getWebClientBuilder()
                .defaultHeaders(headers -> headers.setBasicAuth(basicAuthUsername, basicAuthPassword))
                .build();
    }

    public void pushOrderToSap(String orderId) throws Exception {
        try {
            //查询crm信息
            CrmOrderDto crmOrderDto = this.getOrderById(orderId);
            if ("推送成功".equals(crmOrderDto.getPushedSapStatus())) {
                throw new BusinessException("订单已推送成功,请勿重复推送");
            }
            SapOrderVo sapOrderVo = OrderConvert.convertCrmOrderDtoToSapOrderVo(crmOrderDto, sapEnums);
            log.debug("Pushed sapOrderVo: {}", JacksonUtils.toJsonString(sapOrderVo));
            SapPushOrderResponse sapPushOrderResponse = webClient.post()
                    .uri(this.pushOrderUrl)
                    .contentType(MediaType.APPLICATION_JSON)
                    .accept(MediaType.APPLICATION_JSON)
                    .bodyValue(JacksonUtils.toJsonString(sapOrderVo))
                    .retrieve()
                    .bodyToMono(SapPushOrderResponse.class)
                    .block();
            if (sapPushOrderResponse != null && sapPushOrderResponse.getTYPE().compareTo(SapTypeEnum.SUCCESS) == 0) {
                String sapOrderNumber = sapPushOrderResponse.getVBELN();
                log.debug("推送订单到SAP成功: {}", sapOrderNumber);
                this.writeBackSapOrderNumberToCrm(orderId, sapOrderNumber);
            } else {
                String sapErrorMsg = sapPushOrderResponse != null ? sapPushOrderResponse.getMESSAGE() : "SAP无响应";
                writeBackPushSapErrorMsgToCrm(orderId, sapErrorMsg);
                throw new Exception(sapErrorMsg);
            }
        } catch (Exception e) {
            log.error("推送订单到SAP失败:{}", e.getMessage());
            throw e;
        }
    }

    public CrmOrderDto getOrderById(String orderId) {
        CrmOrderDto crmOrderDto = cloudccOpenApiService
                .cquery(CrmOrderDto.OBJECT_API_NAME, "id = '%s'".formatted(orderId), CrmOrderDto.class)
                .stream().findFirst()
                .orElseThrow(() -> new CloudccOpenApiException("未找到该订单 - orderId:%s".formatted(orderId)));
        List<CrmOrderDto.CrmOrderItemDto> items = this.getOrderItems(orderId);
        if (!items.isEmpty()) {
            crmOrderDto.setItems(items);
        }
        log.debug("查询订单: {}", JacksonUtils.toJsonString(crmOrderDto));
        return crmOrderDto;
    }

    public List<CrmOrderDto.CrmOrderItemDto> getOrderItems(String orderId) {
        return cloudccOpenApiService
                .cquery(CrmOrderDto.CrmOrderItemDto.OBJECT_API_NAME, "orderid = '%s'".formatted(orderId), CrmOrderDto.CrmOrderItemDto.class);
    }

    public void writeBackSapOrderNumberToCrm(String orderId, String sapOrderNumber) {
        CrmOrderDto crmOrderDto = new CrmOrderDto();
        crmOrderDto.setRecordId(orderId);
        crmOrderDto.setSapOrderNumber(sapOrderNumber);
        crmOrderDto.setPushedSapStatus("推送成功");
        CloudccOpenApiUpsertResponse response = cloudccOpenApiService.updateLt(crmOrderDto);
        if (response.successfully() && response.allSuccess()) {
            log.debug("回写SAP订单号 - {} 到CRM订单 - {} 成功", sapOrderNumber, orderId);
        } else {
            log.error("回写SAP订单号 - {} 到CRM订单 - {} 失败", sapOrderNumber, orderId);
            throw new CloudccOpenApiException(response);
        }
    }

    public void writeBackPushSapErrorMsgToCrm(String orderId, String sapErrorMsg) {
        CrmOrderDto crmOrderDto = new CrmOrderDto();
        crmOrderDto.setRecordId(orderId);
        crmOrderDto.setPushedSapStatus("推送失败");
        crmOrderDto.setSapRtnMsg(sapErrorMsg);
        CloudccOpenApiUpsertResponse response = cloudccOpenApiService.updateLt(crmOrderDto);
        if (response.successfully() && response.allSuccess()) {
            log.debug("更新SAP返回的错误消息到CRM订单 - {} 成功", orderId);
        } else {
            log.error("更新SAP返回的错误消息到CRM订单 - {} 失败", orderId);
            throw new CloudccOpenApiException(response);
        }
    }

    public CrmOrderDto getOrderBySapOrderNumber(String sapOrderNumber) {
        return cloudccOpenApiService
                .cquery(CrmOrderDto.OBJECT_API_NAME, "sapOrderNumber = '%s'".formatted(sapOrderNumber), CrmOrderDto.class)
                .stream().findFirst()
                .orElseThrow(() -> new CloudccOpenApiException("未找到该订单 - sapOrderNumber:%s".formatted(sapOrderNumber)));
    }

    public void writeBackSapOrderShippingInfoToCrm(SapOrderShippingInfoVo sapOrderShippingInfoVo) {
        CrmOrderDto crmOrderDto = getOrderBySapOrderNumber(sapOrderShippingInfoVo.getSapOrderNumber());
        String orderId = crmOrderDto.getRecordId();
        List<CrmOrderDto.CrmOrderItemDto> crmOrderItemDtoList = this.getOrderItems(orderId);
        // 以 material 为键建立索引：material -> 该物料在 SAP 中的总发货数量
        Map<String, BigDecimal> sapQtyByMat = sapOrderShippingInfoVo.getItems().stream()
                .collect(Collectors.groupingBy(
                        SapOrderItemShippingInfoVo::getMaterial,
                        Collectors.reducing(
                                BigDecimal.ZERO,
                                item -> new BigDecimal(item.getQuantity()),
                                BigDecimal::add
                        )
                ));
        // 遍历 CRM 明细，按 materialCode 累加 SAP 已发货数量
        List<CrmOrderDto.CrmOrderItemDto> updatedCrmOrderItemDtoList = crmOrderItemDtoList.stream()
                .peek(item -> {
                    BigDecimal sapQty = sapQtyByMat.getOrDefault(item.getMaterialCode(), BigDecimal.ZERO);
                    item.setSapShippedQuantity(item.getSapShippedQuantity() + sapQty.intValue());
                })
                .toList();
        cloudccOpenApiService.updateLt(updatedCrmOrderItemDtoList, true);
    }

}
